package fhv.at.imageprocessing.editors;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.ScrollPane;
import java.awt.Stroke;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyEditor;

import javax.media.jai.PlanarImage;

public class ROIEditor extends Panel implements PropertyEditor {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private int oldX1;
	private int oldY1;
	private int oldX2;
	private int oldY2;
	private final TextField txtX1;
	private final TextField txtY1;
	private final TextField txtX2;
	private final TextField txtY2;
	private final ScrollPane scrollPane;
	private PlanarImage planarImage;
	private ROIEditorHelper roiEditorHelper;
	protected PropertyChangeSupport pcs;

	public ROIEditor() {
		setLayout(null);

		Label lblX1Y1 = new Label("X1 / Y1");
		lblX1Y1.setBounds(10, 11, 46, 14);
		add(lblX1Y1);

		Label lblX2Y2 = new Label("X2 / Y2");
		lblX2Y2.setBounds(10, 36, 46, 14);
		add(lblX2Y2);

		txtX1 = new TextField();
		txtX1.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent ae) {
				editRubberBand(Integer.valueOf(txtX1.getText()),
						Integer.valueOf(txtY1.getText()),
						Integer.valueOf(txtX2.getText()),
						Integer.valueOf(txtY2.getText()));
				valueChanged();
			}
		});
		txtX1.setBounds(66, 8, 46, 20);
		add(txtX1);
		txtX1.setColumns(10);

		txtY1 = new TextField();
		txtY1.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				editRubberBand(Integer.valueOf(txtX1.getText()),
						Integer.valueOf(txtY1.getText()),
						Integer.valueOf(txtX2.getText()),
						Integer.valueOf(txtY2.getText()));
				valueChanged();
			}
		});
		txtY1.setBounds(122, 8, 46, 20);
		add(txtY1);
		txtY1.setColumns(10);

		txtX2 = new TextField();
		txtX2.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				editRubberBand(Integer.valueOf(txtX1.getText()),
						Integer.valueOf(txtY1.getText()),
						Integer.valueOf(txtX2.getText()),
						Integer.valueOf(txtY2.getText()));
				valueChanged();
			}
		});
		txtX2.setBounds(66, 33, 46, 20);
		add(txtX2);
		txtX2.setColumns(10);

		txtY2 = new TextField();
		txtY2.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				editRubberBand(Integer.valueOf(txtX1.getText()),
						Integer.valueOf(txtY1.getText()),
						Integer.valueOf(txtX2.getText()),
						Integer.valueOf(txtY2.getText()));
				valueChanged();
			}
		});
		txtY2.setBounds(122, 33, 46, 20);
		add(txtY2);
		txtY2.setColumns(10);

		final Label label = new Label("X: 0 / Y: 0");
		label.setBounds(234, 11, 100, 20);
		add(label);

		scrollPane = new ScrollPane();
		scrollPane.addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent me) {
				label.setText("X: " + me.getX() + " / Y: " + me.getY());
			}
		});
		scrollPane.addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseDragged(MouseEvent me) {
				label.setText("X: " + me.getX() + " / Y: " + me.getY());
				editRubberBand(Integer.valueOf(txtX1.getText()),
						Integer.valueOf(txtY1.getText()), me.getX(), me.getY());
			}
		});
		scrollPane.addMouseListener(new MouseAdapter() {
			@Override
			public void mousePressed(MouseEvent me) {
				editRubberBand(me.getX(), me.getY(), me.getX(), me.getY());
			}

			@Override
			public void mouseReleased(MouseEvent me) {
				txtX2.setText(String.valueOf(me.getX()));
				txtY2.setText(String.valueOf(me.getY()));
				valueChanged();
			}
		});
		scrollPane.addMouseListener(new MouseAdapter() {
			@Override
			public void mouseExited(MouseEvent e) {
				label.setText("X: 0 / Y: 0");
			}
		});

		scrollPane.setBounds(10, 61, 430, 228);
		add(scrollPane);

		pcs = new PropertyChangeSupport(this);

		setSize(450, 300);
	}

	public ROIEditorHelper getRoiEditorHelper() {
		return roiEditorHelper;
	}

	public void setRoiEditorHelper(ROIEditorHelper roiEditorHelper) {
		this.roiEditorHelper = roiEditorHelper;
	}

	private void valueChanged() {
		roiEditorHelper.setX1(Integer.valueOf(txtX1.getText()));
		roiEditorHelper.setY1(Integer.valueOf(txtY1.getText()));
		roiEditorHelper.setX2(Integer.valueOf(txtX2.getText()));
		roiEditorHelper.setY2(Integer.valueOf(txtY2.getText()));
		this.pcs.firePropertyChange("", null, null);
	}

	private void drawRubberBand() {
		oldX1 = Integer.valueOf(txtX1.getText());
		oldY1 = Integer.valueOf(txtY1.getText());
		oldX2 = Integer.valueOf(txtX2.getText());
		oldY2 = Integer.valueOf(txtY2.getText());

		Graphics2D g = setGraphics();
		g.drawRect(oldX1, oldY1, oldX2 - oldX1, oldY2 - oldY1);

	}

	private void editRubberBand(int newX1, int newY1, int newX2, int newY2) {
		Graphics2D g = setGraphics();
		g.drawRect(oldX1, oldY1, oldX2 - oldX1, oldY2 - oldY1);
		g.drawRect(newX1, newY1, newX2 - newX1, newY2 - newY1);

		txtX1.setText(String.valueOf(newX1));
		txtY1.setText(String.valueOf(newY1));
		txtX2.setText(String.valueOf(newX2));
		txtY2.setText(String.valueOf(newY2));

		oldX1 = newX1;
		oldY1 = newY1;
		oldX2 = newX2;
		oldY2 = newY2;
	}

	private Graphics2D setGraphics() {
		Graphics2D g = (Graphics2D) scrollPane.getGraphics();
		Stroke drawingStroke = new BasicStroke(3, BasicStroke.CAP_BUTT,
				BasicStroke.JOIN_BEVEL, 0, new float[] { 9 }, 0);
		g.setStroke(drawingStroke);
		g.setXORMode(Color.WHITE);
		return g;
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		drawImage();
	}

	private void drawImage() {
		if (planarImage != null) {
			Graphics g = scrollPane.getGraphics();
			g.drawImage(planarImage.getAsBufferedImage(), 0, 0, this);
			scrollPane.setBounds(10, 61, planarImage.getWidth(),
					planarImage.getHeight());
			setSize(planarImage.getWidth(), planarImage.getHeight());

			drawRubberBand();
		}
	}

	@Override
	public void addPropertyChangeListener(PropertyChangeListener pcl) {
		this.pcs.addPropertyChangeListener(pcl);
	}

	@Override
	public String getAsText() {
		return "P1(" + txtX1 + "," + txtY1 + "), P2(" + txtX2 + "," + txtY2
				+ ")";
	}

	@Override
	public Component getCustomEditor() {
		return this;
	}

	@Override
	public String getJavaInitializationString() {
		return null;
	}

	@Override
	public String[] getTags() {
		return null;
	}

	@Override
	public Object getValue() {
		roiEditorHelper.setX1(Integer.valueOf(txtX1.getText()));
		roiEditorHelper.setY1(Integer.valueOf(txtY1.getText()));
		roiEditorHelper.setX2(Integer.valueOf(txtX2.getText()));
		roiEditorHelper.setY2(Integer.valueOf(txtY2.getText()));
		return roiEditorHelper;
	}

	@Override
	public boolean isPaintable() {
		return true;
	}

	@Override
	public void paintValue(Graphics g, Rectangle rec) {
		g.setColor(Color.BLACK);
		g.drawRect(0, 0, rec.width - 1, rec.height - 1);
	}

	@Override
	public void setAsText(String text) throws IllegalArgumentException {
	}

	@Override
	public void setValue(Object value) {
		roiEditorHelper = (ROIEditorHelper) value;
		txtX1.setText(String.valueOf(roiEditorHelper.getX1()));
		txtY1.setText(String.valueOf(roiEditorHelper.getY1()));
		txtX2.setText(String.valueOf(roiEditorHelper.getX2()));
		txtY2.setText(String.valueOf(roiEditorHelper.getY2()));
		planarImage = roiEditorHelper.getPlanarImage();
	}

	@Override
	public boolean supportsCustomEditor() {
		return true;
	}

}
